import datetime
import json

from django.contrib import messages
from django.core.files.uploadedfile import UploadedFile
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Q
from django.http import HttpRequest

from main.forms import GeneratedForm, MeasureSheetFrom
from main.models import Client, FormStructures, Request, RequestAttachment, User


class JSONEncoder(DjangoJSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime("%Y.%m.%d %H:%M")
        return super().default(obj)


def get_all_clients():
    return Client.objects.all()


def get_structure(name: str) -> list[dict] | None:
    try:
        data = FormStructures.objects.get(name=name).structure
        return data
    except FormStructures.DoesNotExist:
        return None


def get_extra_fields(name: str, initial: dict) -> GeneratedForm | None:
    if structure := get_structure(name):
        return GeneratedForm(structure, initial=initial)
    return None


def get_all_requests(search_query: str = "", archived: bool = False):
    if search_query:
        try:
            reqs = Request.objects.filter(
                Q(first_name__contains=search_query)
                | Q(phone_number__contains=search_query)
                | Q(note__contains=search_query)
            )
        except Request.DoesNotExist:
            return None
    elif archived:
        reqs = Request.objects.filter(archived=True)
    else:
        reqs = Request.objects.exclude(archived=True)

    return reqs


def update_measure_sheet(req: Request, form: MeasureSheetFrom) -> bool:
    if not req.archived:
        req.measure_sheet = json.dumps(form.cleaned_data)
        req.save()
        return True
    return False


def request_status_change(req: Request, new_status: str) -> bool:
    if new_status in req.RequestStatus.names:
        req.status = req.RequestStatus[new_status]
        req.archived = False
        req.save()
        return True
    elif new_status == "fake" and not req.archived:
        req.status = req.RequestStatus.FAKE
        req.archived = True
        req.save()
        return True
    elif new_status == "in_archive" and not req.archived:
        req.archived = True
        req.save()
        return True
    return False


def request_upload_attachs(
    request: HttpRequest, req: Request, files: list[UploadedFile]
) -> bool:
    if req.archived:
        return False
    for f in files:
        assert isinstance(request.user, User)
        file_instance = RequestAttachment(
            file=f,
            request=req,
            name=f.name,
            content_type=f.content_type,
            creator=request.user,
        )
        file_instance.save()
        messages.success(request, f'Файл "{f.name}" успешно загружен!')
    return True
